package com.hyk.commonLib.common.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Environment;
import android.text.format.Formatter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 贺玉琨 on 2019/3/13.
 */
public class FileUtils {
    public static String getCacheDir() {
        return AppUtils.getAppContext().getCacheDir().getAbsolutePath();
    }

    /**
     * is sd card available.
     *
     * @return true if available
     */
    public boolean isSdCardAvailable() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }

    /**
     * 重命名文件\文件夹
     */
    public static boolean rename(String filepath, String newName) {
        File file = new File(filepath);
        return file.exists() && file.renameTo(new File(file.getParentFile(), newName));
    }

    /**
     * 移动文件\文件夹
     */
    public static boolean move(String oldPath, String newPath) {
        File oldFile = new File(oldPath);
        File newFile = new File(newPath);
        return oldFile.exists() && (newFile.getParentFile().exists() || newFile.getParentFile().mkdirs()) && oldFile.renameTo(newFile);
    }

    /**
     * 创建文件夹(支持覆盖已存在的同名文件夹)
     */
    public static boolean createFolder(String filePath, boolean recreate) {
        String folderName = getFolderName(filePath);
        if (folderName == null || folderName.length() == 0 || folderName.trim().length() == 0) {
            return false;
        }
        File folder = new File(folderName);
        if (folder.exists()) {
            if (recreate) {
                deleteFile(folderName);
                return folder.mkdirs();
            } else {
                return true;
            }
        } else {
            return folder.mkdirs();
        }
    }

    public static boolean deleteFile(File file) {
        if (!file.exists()) {
            return false;
        } else {
            if (file.isFile()) {
                // 为文件时调用删除文件方法
                return file.delete();
            } else {
                String filePath = file.getAbsolutePath();
                boolean flag;
                //如果filePath不以文件分隔符结尾，自动添加文件分隔符
                if (!filePath.endsWith(File.separator)) {
                    filePath = filePath + File.separator;
                }
                File dirFile = new File(filePath);
                if (!dirFile.exists() || !dirFile.isDirectory()) {
                    return false;
                }
                flag = true;
                File[] files = dirFile.listFiles();
                if (files == null) return true;
                //遍历删除文件夹下的所有文件(包括子目录)
                for (File value : files) {
                    flag = deleteFile(value.getAbsolutePath());
                    if (!flag) break;
                }
                if (!flag) return false;
                //删除当前空目录
                return dirFile.delete();
            }
        }
    }

    /**
     * 根据路径删除指定的目录或文件，无论存在与否
     *
     * @param filePath 要删除的目录或文件
     * @return 删除成功返回 true，否则返回 false。
     */
    public static boolean deleteFile(String filePath) {
        return deleteFile(new File(filePath));
    }

    /**
     * 获取文件夹名称
     */
    public static String getFolderName(String filePath) {
        if (filePath == null || filePath.length() == 0 || filePath.trim().length() == 0) {
            return filePath;
        }
        int filePos = filePath.lastIndexOf(File.separator);
        return (filePos == -1) ? "" : filePath.substring(0, filePos);
    }

    /**
     * 格式化文件大小
     */
    public static String formatFileSize(long size) {
        return Formatter.formatFileSize(AppUtils.getAppContext(), size);
    }

    /**
     * 将输入流写入到文件
     */
    public static void stream2File(InputStream is, File file) {
        byte[] b = new byte[1024];
        int len;
        try (FileOutputStream os = new FileOutputStream(file)) {
            while ((len = is.read(b)) != -1) {
                os.write(b, 0, len);
                os.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 指定目录写入文件内容
     *
     * @param filePath 文件路径+文件名
     * @param bitmap   文件内容
     */
    public static void saveAsJPEG(Bitmap bitmap, String filePath) throws IOException {

        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
        }
    }

    /**
     * 指定目录写入文件内容
     *
     * @param filePath 文件路径+文件名
     * @param bitmap   文件内容
     */
    public static void saveAsPNG(Bitmap bitmap, String filePath) throws IOException {

        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
            fos.flush();
        }
    }

    /**
     * 写入应用程序包files目录下文件
     *
     * @param fileName 文件名称
     * @param content  文件内容
     */
    public static void write(String fileName, String content) {
        try (FileOutputStream outStream = AppUtils.getAppContext().openFileOutput(fileName, Context.MODE_PRIVATE)) {
            outStream.write(content.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 写入应用程序包files目录下文件
     *
     * @param fileName 文件名称
     * @param modeType 文件写入模式（Context.MODE_PRIVATE、Context.MODE_APPEND、Context.
     *                 MODE_WORLD_READABLE、Context.MODE_WORLD_WRITEABLE）
     * @param content  文件内容
     */
    public static void write(String fileName, byte[] content, int modeType) {
        try (FileOutputStream outStream = AppUtils.getAppContext().openFileOutput(fileName, modeType)) {
            outStream.write(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 指定编码将内容写入目标文件
     *
     * @param target   目标文件
     * @param content  文件内容
     * @param encoding 写入文件编码
     */
    public static void write(File target, String content, String encoding) throws IOException {
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdirs();
        }
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(target, false), encoding))) {
            writer.write(content);
        }
    }

    /**
     * 指定目录写入文件内容
     *
     * @param filePath 文件路径+文件名
     * @param content  文件内容
     */
    public static void write(String filePath, byte[] content) throws IOException {

        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(content);
            fos.flush();
        }
    }

    /**
     * 写入文件
     *
     * @param inputStream 下载文件的字节流对象
     * @param filePath    文件的存放路径
     *                    (带文件名称)
     */
    public static File write(InputStream inputStream, String filePath) throws IOException {
        // 在指定目录创建一个空文件并获取文件对象
        File mFile = new File(filePath);
        if (!mFile.getParentFile().exists())
            mFile.getParentFile().mkdirs();
        byte[] buffer = new byte[4 * 1024];
        OutputStream outputStream = new FileOutputStream(mFile);
        try {
            int lenght;
            while ((lenght = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, lenght);
            }
            outputStream.flush();
            return mFile;
        } finally {
            try {
                inputStream.close();
                outputStream.close();
            } catch (IOException ignored) {
            }
        }
    }

    /**
     * 以行为单位读取文件内容，一次读一整行，常用于读面向行的格式化文件
     *
     * @param filePath 文件路径
     */
    public static String readFileByLines(String filePath) {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), System.getProperty("file.encoding")))) {
            String tempString;
            while ((tempString = reader.readLine()) != null) {
                sb.append(tempString).append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();

    }

    /**
     * 以行为单位读取文件内容，一次读一整行，常用于读面向行的格式化文件
     *
     * @param filePath 文件路径
     * @param encoding 写文件编码
     */
    public static String readFileByLines(String filePath, String encoding) {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), encoding))) {
            String tempString;
            while ((tempString = reader.readLine()) != null) {
                sb.append(tempString);
                sb.append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return sb.toString();
    }

    /**
     * 保存内容
     *
     * @param filePath 文件路径
     * @param content  保存的内容
     * @throws IOException
     */
    public static void saveToFile(String filePath, String content) throws IOException {
        saveToFile(filePath, content, System.getProperty("file.encoding"));
    }

    /**
     * 指定编码保存内容
     *
     * @param filePath 文件路径
     * @param content  保存的内容
     * @param encoding 写文件编码
     * @throws IOException
     */
    public static void saveToFile(String filePath, String content, String encoding) throws IOException {
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), encoding))) {
            writer.write(content);
        }
    }

    /**
     * 指定编码保存内容
     *
     * @param filePath 文件路径
     * @throws IOException
     */
    public static void saveToFile(String filePath, byte[] bytes) throws IOException {
        File file = new File(filePath);
        saveToFile(file, bytes);
    }

    /**
     * 指定编码保存内容
     *
     * @throws IOException
     */
    public static void saveToFile(File file, byte[] bytes) throws IOException {
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try (OutputStream os = new FileOutputStream(file)) {
            os.write(bytes);
            os.flush();
        }
    }

    /**
     * 追加文本
     *
     * @param content 需要追加的内容
     * @param file    待追加文件源
     * @throws IOException
     */
    public static void appendToFile(String content, File file) throws IOException {
        appendToFile(content, file, System.getProperty("file.encoding"));
    }

    /**
     * 追加文本
     *
     * @param content  需要追加的内容
     * @param file     待追加文件源
     * @param encoding 文件编码
     * @throws IOException
     */
    public static void appendToFile(String content, File file, String encoding) throws IOException {
        BufferedWriter writer = null;
        try {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(file, true), encoding));
            writer.write(content);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param filePath 文件路径
     * @return 是否存在
     */
    public static Boolean isExist(String filePath) {
        boolean flag = false;
        try {
            File file = new File(filePath);
            flag = isExist(file);
        } catch (Exception ignored) {
        }

        return flag;
    }

    /**
     * 判断文件是否存在
     */
    public static Boolean isExist(File file) {
        if (file == null) return false;
        boolean flag = false;
        try {
            if (file.exists()) {
                flag = true;
            }
        } catch (Exception ignored) {
        }

        return flag;
    }

    /**
     * 读取指定目录文件的文件内容
     *
     * @param fileName 文件名称
     * @return 文件内容
     */
    @SuppressWarnings("resource")
    public static String read(String fileName, String encoding) throws IOException {
        FileInputStream inStream = new FileInputStream(fileName);
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        byte[] data = outStream.toByteArray();
        return new String(data, encoding);
    }

    /**
     * 读取raw目录的文件内容
     *
     * @param rawFileId raw文件名id
     */
    public static String readRawValue(int rawFileId) {
        String result = "";
        try {
            InputStream is = ResUtils.getResource().openRawResource(rawFileId);
            int len = is.available();
            byte[] buffer = new byte[len];
            is.read(buffer);
            result = new String(buffer, StandardCharsets.UTF_8);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 读取assets目录的文件内容
     *
     * @param fileName 文件名称，包含扩展名
     */
    public static String readAssetsValue(String fileName) {
        String result = "";
        try {
            InputStream is = ResUtils.getResource().getAssets().open(fileName);
            int len = is.available();
            byte[] buffer = new byte[len];
            is.read(buffer);
            result = new String(buffer, StandardCharsets.UTF_8);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 读取assets目录的文件内容
     *
     * @param fileName 文件名称，包含扩展名
     */
    public static List<String> readAssetsListValue(String fileName) {
        List<String> list = new ArrayList<>();
        try {
            InputStream in = ResUtils.getResource().getAssets().open(fileName);
            BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            String str;
            while ((str = br.readLine()) != null) {
                list.add(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    public static boolean copy(String pathFrom, String pathTo) {
        return copy(new File(pathFrom), new File(pathTo));
    }

    public static boolean copy(File fileFrom, File fileTo) {
        if (!fileFrom.exists()) {
            return false;
        }
        if (fileFrom.getAbsolutePath().equalsIgnoreCase(fileTo.getAbsolutePath())) {
            return false;
        }
        if (!fileTo.getParentFile().exists()) {
            fileTo.getParentFile().mkdirs();
        }
        try (
                FileChannel inputChannel = new FileInputStream(fileFrom).getChannel();
                FileChannel outputChannel = new FileOutputStream(fileTo).getChannel()
        ) {
            inputChannel.transferTo(0, inputChannel.size(), outputChannel);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}
